﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Xenta.Utils
{
    /// <summary>
    /// Represents the CSV(Comma-separated values) helper.
    /// </summary>
    public static class CsvHelper
    {
        /// <summary>
        /// Splits the provider string into an array of fields.
        /// </summary>
        /// <param name="s">The string to split.</param>
        /// <param name="separator">The CSV delimeter(',' by default).</param>
        /// <returns>An array of fields.</returns>
        public static string[] Split(string s, char separator = ',')
        {
            var fields = new List<String>();
            bool inColumn = false;
            bool inQuotes = false;
            var sb = new StringBuilder();

            for(int i = 0; i < s.Length; i++)
            {
                char character = s[i];

                if(!inColumn)
                {
                    if(character == '"')
                    {
                        inQuotes = true;
                        inColumn = true;
                    }
                    else if(inQuotes || character != separator)
                    {
                        sb.Append(character);
                        inColumn = true;
                    }
                    else
                    {
                        fields.Add(String.Empty);
                    }
                    continue;
                }
                if(inQuotes)
                {
                    if(character == '"')
                    {
                        if((i + 1) == s.Length)
                        {
                            inQuotes = false;
                            break;
                        }
                        else if(s[i + 1] == separator)
                        {
                            inQuotes = false;
                            inColumn = false;
                        }
                        i++;
                    }
                }
                else if(character == separator)
                {
                    inColumn = false;
                }
                if(!inColumn)
                {
                    fields.Add(sb.ToString());
                    sb.Remove(0, sb.Length);
                }
                else
                {
                    sb.Append(character);
                }
            }
            if(inColumn)
                fields.Add(sb.ToString());
            else
                fields.Add(String.Empty);
            return fields.ToArray();
        }

        /// <summary>
        /// Merges an array of fields into a string.
        /// </summary>
        /// <param name="fields">An array of fields to merge.</param>
        /// <param name="separator">The CSV delimeter(',' by default).</param>
        /// <returns>The result string.</returns>
        public static string Merge(string[] fields, char separator = ',')
        {
            var sb = new StringBuilder();

            for(int i = 0; i < fields.Length; i++)
            {
                string field = fields[i];
                string value = field;
                bool quotesRequired = field.Contains(separator);
                bool escapeQuotes = field.Contains('"');

                if(value.Contains("\r") || value.Contains("\n"))
                {
                    value = value.Replace("\r\n", String.Empty);
                    value = value.Replace("\r", String.Empty);
                    value = value.Replace("\n", String.Empty);
                }
                if(escapeQuotes)
                    value = value.Replace('"'.ToString(), new String('"', 2));

                sb.AppendFormat("{1}{0}{1}{2}", value,
                    quotesRequired || escapeQuotes ? '"'.ToString() : String.Empty,
                    i < fields.Count() - 1 ? separator.ToString() : String.Empty);
            }
            return sb.ToString();
        }
    }
}
